#ifndef UnixSystem_First
#ifdef __GNUG__
#pragma interface
#endif
#define UnixSystem_First

#include "System.h"
#include "SysEvtHandler.h"
#include "Timer.h"
#include "String.h"
#include "ET_stdio.h"

class SeqCollection;
class SysAlarmHandler;

//---- fd_set ------------------------------------------------------------------

#define HOWMANY(x, y)   (((x)+((y)-1))/(y))
#define NFDBITS (sizeof(long) * 8)      /* bits per mask */

struct fd_set {
	long fds_bits[HOWMANY(256, NFDBITS)];
	fd_set()
		{ memset(fds_bits, 0, sizeof(fds_bits)); }
	void Zero()
		{ memset(fds_bits, 0, sizeof(fds_bits)); }
	void Set(int n)
		{ fds_bits[n/NFDBITS] |= (1 << (n % NFDBITS)); }
	void Clr(int n)
		{ fds_bits[n/NFDBITS] &= ~(1 << (n % NFDBITS)); }
	int IsSet(int n)
		{ return fds_bits[n/NFDBITS] & (1 << (n % NFDBITS)); }
};

//---- UnixSystem --------------------------------------------------------------

class UnixSystem: public System {
friend SysAlarmHandler;
public:
	MetaDef(UnixSystem);
	UnixSystem();
	~UnixSystem();

	//---- Misc -------------------------------------------------
	bool Init();
	const char *GetError();
	const char *Hostname();

	//---- EventLoop --------------------------------------------
	void DispatchOneEvent();
	void DispatchSignals(Signals sig);
	void AddFileHandler(FileHandler*);
	FileHandler *RemoveFileHandler(FileHandler*);
	void AddSignalHandler(SignalHandler*);
	SignalHandler *RemoveSignalHandler(SignalHandler*);
	void CheckChilds();
	bool CheckSignals(bool sync);

	//---- Processes --------------------------------------------
	int GetPid();
	int Exec(const char *shellcmd);
	FILE *OpenPipe(const char *shellcmd, const char *mode);
	int ClosePipe(FILE *pipe);
	void Exit(int code, bool mode);
	void Abort(int code);

	//---- environment manipulation -----------------------------
	const char *Getenv(const char *name);
	void Setenv(const char *name, const char *value);
	const char *GetEnvAt(int ix);

	//---- Directories ------------------------------------------
	void *MakeDirectory(const char *name);
	void FreeDirectory(void *dirp);
	const char *GetDirEntry(void *dirp);
	bool ChangeDirectory(const char *path);
	const char *WorkingDirectory();
	const char *HomeDirectory();

	//---- Paths & Files ----------------------------------------
	bool ExpandPathName(char *patbuf, int buflen);
	bool AccessPathName(const char *path, int mode= 0);
	void Rename(const char *from, const char *to);
	int GetPathInfo(const char *path, u_long *id, u_long *size,
		u_long *flags, u_long *modtime);

	//---- Dynamic Loading --------------------------------------
	Object *Load(const char *progname, const char *name);

	//---- Time & Date
	Time Now();
	void AddTimer(Timer *ti);
	bool RemoveTimer(Timer *ti);
	void DispatchTimers();

	//---- RPC --------------------------------------------------
	int ConnectService(const char *servername, const char *servicename);
	int OpenConnection(const char *server, const char *service);
	int AnnounceTcpService(const char *servicename);
	int AnnounceUnixService(const char *servername);
	int AcceptConnection(int sock);

	//---- Pseudo TTYs ------------------------------------------
	PttyImpl *MakePttyImpl();

protected:
	SeqCollection *zombieHandler;
	fd_set readmask, writemask, readready, writeready, signals;
	int nfd, maxrfd, maxwfd, sigcnt;
	char *wdpath, hostname[30];
	bool insideNotify;
};

#endif
